#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "globals.h"
#include "geometry.h"
#include "polygon.h"
#include "voronoi.h"
#include "distance.h"
#include "sgidrawi.h"
#include "sweep.h"

static int 				numVoronoi = 0;
static int				maxVoronoi = 0;
static storedVoronoi	*vorPoints = NULL;

int 				numBackVoronoi = 0;
storedVoronoi	*backVorPoints = NULL;

#define ScreenLimits	1000.0

int recordVoronoiVertex (Pt *point, spokeInfo *spoke1, spokeInfo
	*spoke2, spokeInfo *spoke3)
{
	storedVoronoi	*vorList;
	int				*count;

	if (demoPass == True) {
		vorList = vorPoints;
		count = &numVoronoi;
	}
	else {
		vorList = backVorPoints;
		count = &numBackVoronoi;
	}

	if (vorList == NULL) {
		printf ("Going through an empty list!\n");
		return (0);
	}

	if (numVoronoi < maxVoronoi) {
		*count = *count + 1;
		PointAssign (vorList[*count].voronoi, *point);
		PointAssign (vorList[*count].attachment[0], spoke1->attachment);
		PointAssign (vorList[*count].attachment[1], spoke2->attachment);
		PointAssign (vorList[*count].attachment[2], spoke3->attachment);

		vorList[*count].attachIdx[0] = spoke1->attachIndex;
		vorList[*count].attachIdx[1] = spoke2->attachIndex;
		vorList[*count].attachIdx[2] = spoke3->attachIndex;
		
		vorList[*count].generator[0] = spoke1->attachPolygon;
		vorList[*count].generator[1] = spoke2->attachPolygon;
		vorList[*count].generator[2] = spoke3->attachPolygon;

		vorList[*count].type = NormalVoronoi;
		vorList[*count].bisector[0] = NULL;
		vorList[*count].bisector[1] = NULL;
		vorList[*count].bisector[2] = NULL;

		vorList[*count].bottleneck[0] = NULL;
		vorList[*count].bottleneck[1] = NULL;
		vorList[*count].bottleneck[2] = NULL;

		return (*count);
	}
	else {
		printf ("Have exceeded the maximum static allocation for Voronoi "
			"vertices\n");
		return (0);
	}
}

void
initVoronoi (int limit)
{
	maxVoronoi = limit * 4;

	if (vorPoints == NULL) {
		vorPoints = (storedVoronoi *)malloc(maxVoronoi * sizeof(storedVoronoi));
		backVorPoints = (storedVoronoi *)
				malloc(maxVoronoi * sizeof(storedVoronoi));
	}

	numVoronoi = 0;
	numBackVoronoi = 0;
}

void
endVoronoi()
{
	int	i, j;

	for (i = 1; i <= numVoronoi; i++) {
		for (j = 0; j < 3; j++) {
			if (vorPoints[i].bisector[j] != NULL) {
				free (vorPoints[i].bisector[j]);
				vorPoints[i].bisector[j] = NULL;
			}
			if (vorPoints[i].bottleneck[j] != NULL) {
				free (vorPoints[i].bottleneck[j]);
				vorPoints[i].bottleneck[j] = NULL;
			}
		}
	}

	for (i = 1; i <= numBackVoronoi; i++) {
		for (j = 0; j < 3; j++) {
			if (backVorPoints[i].bisector[j] != NULL) {
				free (backVorPoints[i].bisector[j]);
				backVorPoints[i].bisector[j] = NULL;
			}
			if (backVorPoints[i].bottleneck[j] != NULL) {
				free (backVorPoints[i].bottleneck[j]);
				backVorPoints[i].bottleneck[j] = NULL;
			}
		}
	}

	if (vorPoints != NULL) {
		free (vorPoints); vorPoints = NULL;
		free (backVorPoints); backVorPoints = NULL;
	}

	numVoronoi = 0;
	numBackVoronoi = 0;
}

/*	Find a point along driveLine that is to the right side of
	testLine and is off the displayable screen. */

void
awayPoint(Line *driveLine, Line *testLine, Pt *testPt)
{
	Line	highLine, lowLine;

	if (MyAbs(LineSlope(*driveLine)) < 1) {
		highLine.w = ScreenLimits;
		highLine.x = 1.0;
		highLine.y = 0.0;

		IntersectionOf(&highLine, driveLine, testPt);
		if (testPt->w < 0) {
			testPt->w *= -1; testPt->x *= -1; testPt->y *= -1;
		}
		if (LineSide (testLine, testPt) == LeftSide) {
			lowLine.w = ScreenLimits;
			lowLine.x = -1.0;
			lowLine.y = 0.0;

			IntersectionOf(&lowLine, driveLine, testPt);
			if (testPt->w < 0) {
				testPt->w *= -1; testPt->x *= -1; testPt->y *= -1;
			}
		}
	}
	else {
		highLine.w = ScreenLimits;
		highLine.x = 0.0;
		highLine.y = -1.0;

		IntersectionOf(&highLine, driveLine, testPt);
		if (testPt->w < 0) {
			testPt->w *= -1; testPt->x *= -1; testPt->y *= -1;
		}
		if (LineSide(testLine, testPt) == LeftSide) {
			lowLine.w = ScreenLimits;
			lowLine.x = 0.0;
			lowLine.y = 1.0;

			IntersectionOf(&lowLine, driveLine, testPt);
			if (testPt->w < 0) {
				testPt->w *= -1; testPt->x *= -1; testPt->y *= -1;
			}
		}
	}
}


void
reverseLine(Line *line, Line *reverse)
{
	reverse->w = line->w * -1;
	reverse->x = line->x * -1;
	reverse->y = line->y * -1;
}

